#include <avr/pgmspace.h>

static uint8_t konami_font[] PROGMEM = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xBE, 0xBE, 0x0E, 0x00, 0x00, 
  0x00, 0x00, 0x0E, 0x06, 0x00, 0x0E, 0x06, 0x00, 
  0x00, 0x28, 0xFE, 0xFE, 0x28, 0xFE, 0xFE, 0x28, 
  0x00, 0x08, 0x5C, 0x54, 0xFE, 0x54, 0x74, 0x20, 
  0x00, 0x84, 0x4A, 0x24, 0x10, 0x48, 0xA4, 0x42, 
  0x00, 0x60, 0x9C, 0x9A, 0xB2, 0xEC, 0x40, 0xA0, 
  0x00, 0x00, 0x16, 0x0E, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x38, 0x7C, 0xC6, 0x82, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x82, 0xC6, 0x7C, 0x38, 0x00, 
  0x00, 0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, 
  0x00, 0x00, 0x10, 0x10, 0x7C, 0x10, 0x10, 0x00, 
  0x00, 0x00, 0x80, 0xE0, 0x60, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 
  0x00, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0x00, 
  0x00, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 
  0x00, 0x38, 0x7C, 0xC2, 0x82, 0x86, 0x7C, 0x38, 
  0x00, 0x00, 0x80, 0x84, 0xFE, 0xFE, 0x80, 0x80, 
  0x00, 0xC4, 0xE6, 0xF2, 0xB2, 0xBA, 0x9E, 0x8C, 
  0x00, 0x40, 0xC2, 0x92, 0x9A, 0x9E, 0xF6, 0x62, 
  0x00, 0x30, 0x38, 0x2C, 0x26, 0xFE, 0xFE, 0x20, 
  0x00, 0x4E, 0xCE, 0x8A, 0x8A, 0x8A, 0xFA, 0x70, 
  0x00, 0x78, 0xFC, 0x96, 0x92, 0x92, 0xF2, 0x60, 
  0x00, 0x06, 0x06, 0xE2, 0xF2, 0x1A, 0x0E, 0x06, 
  0x00, 0x6C, 0x9E, 0x9A, 0xB2, 0xB2, 0xEC, 0x60, 
  0x00, 0x0C, 0x9E, 0x92, 0x92, 0xD2, 0x7E, 0x3C, 
  0x00, 0x00, 0x00, 0x6C, 0x6C, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x80, 0xEC, 0x6C, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0x82, 0x00, 
  0x00, 0x00, 0x28, 0x28, 0x28, 0x28, 0x28, 0x00, 
  0x00, 0x00, 0x82, 0xC6, 0x6C, 0x38, 0x10, 0x00, 
  0x00, 0x0C, 0x0E, 0xA6, 0xA6, 0xB6, 0x1E, 0x0C, 
  0x00, 0x38, 0x7C, 0xC6, 0x82, 0x9A, 0xDE, 0x5C, 
  0x00, 0xF8, 0xFC, 0x26, 0x22, 0x26, 0xFC, 0xF8, 
  0x00, 0xFE, 0xFE, 0x92, 0x92, 0x92, 0xFE, 0x6C, 
  0x00, 0x38, 0x7C, 0xC6, 0x82, 0x82, 0xC6, 0x44, 
  0x00, 0xFE, 0xFE, 0x82, 0x82, 0xC6, 0x7C, 0x38, 
  0x00, 0xFE, 0xFE, 0x92, 0x92, 0x92, 0x92, 0x82, 
  0x00, 0xFE, 0xFE, 0x12, 0x12, 0x12, 0x12, 0x02, 
  0x00, 0x38, 0x7C, 0xC6, 0x82, 0x92, 0xF2, 0xF2, 
  0x00, 0xFE, 0xFE, 0x10, 0x10, 0x10, 0xFE, 0xFE, 
  0x00, 0x00, 0x82, 0x82, 0xFE, 0xFE, 0x82, 0x82, 
  0x00, 0x40, 0xC0, 0x80, 0x80, 0x80, 0xFE, 0x7E, 
  0x00, 0xFE, 0xFE, 0x30, 0x78, 0xEC, 0xC6, 0x82, 
  0x00, 0xFE, 0xFE, 0x80, 0x80, 0x80, 0x80, 0x80, 
  0x00, 0xFE, 0xFE, 0x1C, 0x38, 0x1C, 0xFE, 0xFE, 
  0x00, 0xFE, 0xFE, 0x1C, 0x38, 0x70, 0xFE, 0xFE, 
  0x00, 0x7C, 0xFE, 0x82, 0x82, 0x82, 0xFE, 0x7C, 
  0x00, 0xFE, 0xFE, 0x22, 0x22, 0x22, 0x3E, 0x1C, 
  0x00, 0x7C, 0xFE, 0x82, 0xA2, 0xE2, 0x7E, 0xBC, 
  0x00, 0xFE, 0xFE, 0x22, 0x62, 0xF2, 0xDE, 0x9C, 
  0x00, 0x4C, 0xDE, 0x92, 0x92, 0x96, 0xF4, 0x60, 
  0x00, 0x00, 0x02, 0x02, 0xFE, 0xFE, 0x02, 0x02, 
  0x00, 0x7E, 0xFE, 0x80, 0x80, 0x80, 0xFE, 0x7E, 
  0x00, 0x1E, 0x3E, 0x70, 0xE0, 0x70, 0x3E, 0x1E, 
  0x00, 0xFE, 0xFE, 0x70, 0x38, 0x70, 0xFE, 0xFE, 
  0x00, 0xC6, 0xEE, 0x7C, 0x38, 0x7C, 0xEE, 0xC6, 
  0x00, 0x00, 0x0E, 0x1E, 0xF0, 0xF0, 0x1E, 0x0E, 
  0x00, 0xC2, 0xE2, 0xF2, 0xBA, 0x9E, 0x8E, 0x86, 
  0x00, 0x00, 0x00, 0xFE, 0xFE, 0x82, 0x82, 0x00, 
  0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 
  0x00, 0x00, 0x82, 0x82, 0xFE, 0xFE, 0x00, 0x00, 
  0x00, 0x00, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x06, 0x0C, 0x18, 0x00, 
  0xFC, 0x42, 0x89, 0x41, 0x81, 0x49, 0x82, 0x7C, 
  0x00, 0x00, 0x1E, 0x20, 0x40, 0x46, 0x48, 0x48, 
  0x48, 0x48, 0x46, 0x40, 0x20, 0x1E, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xF0, 0x08, 0x04, 0xC4, 0x24, 
  0x24, 0x24, 0x24, 0xC4, 0x04, 0x08, 0xF0, 0x00, 
  0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 
  0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, 
  0x3C, 0x42, 0x95, 0xA1, 0xA1, 0x95, 0x42, 0x3C, 
  0x00, 0x00, 0x82, 0x82, 0xFE, 0xFE, 0x82, 0x82, 
  0x00, 0x40, 0xC0, 0x80, 0x80, 0x80, 0xFE, 0x7E, 
  0x00, 0xFE, 0xFE, 0x30, 0x78, 0xEC, 0xC6, 0x82, 
  0x00, 0xFE, 0xFE, 0x80, 0x80, 0x80, 0x80, 0x80, 
  0x00, 0xFE, 0xFE, 0x1C, 0x38, 0x1C, 0xFE, 0xFE, 
  0x00, 0xFE, 0xFE, 0x1C, 0x38, 0x70, 0xFE, 0xFE, 
  0x00, 0x7C, 0xFE, 0x82, 0x82, 0x82, 0xFE, 0x7C, 
  0x00, 0xFE, 0xFE, 0x22, 0x22, 0x22, 0x3E, 0x1C, 
  0x00, 0x7C, 0xFE, 0x82, 0xA2, 0xE2, 0x7E, 0xBC, 
  0x00, 0xFE, 0xFE, 0x22, 0x62, 0xF2, 0xDE, 0x9C, 
  0x00, 0x4C, 0xDE, 0x92, 0x92, 0x96, 0xF4, 0x60, 
  0x00, 0x00, 0x02, 0x02, 0xFE, 0xFE, 0x02, 0x02, 
  0x00, 0x7E, 0xFE, 0x80, 0x80, 0x80, 0xFE, 0x7E, 
  0x00, 0x1E, 0x3E, 0x70, 0xE0, 0x70, 0x3E, 0x1E, 
  0x00, 0xFE, 0xFE, 0x70, 0x38, 0x70, 0xFE, 0xFE, 
  0x00, 0xC6, 0xEE, 0x7C, 0x38, 0x7C, 0xEE, 0xC6, 
  0x00, 0x00, 0x0E, 0x1E, 0xF0, 0xF0, 0x1E, 0x0E, 
  0x00, 0xC2, 0xE2, 0xF2, 0xBA, 0x9E, 0x8E, 0x86, 
  0x00, 0x00, 0x10, 0xFE, 0xFE, 0x82, 0x82, 0x00, 
  0x00, 0x00, 0x00, 0xFE, 0xFE, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x82, 0x82, 0xFE, 0xFE, 0x10, 0x00, 
  0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
};


static char sin_lut[] PROGMEM = {
  0x00,0x03,0x06,0x09,0x0c,0x0f,0x12,0x15,0x19,0x1c,0x1f,0x22,0x25,0x28,0x2b,0x2e,
  0x31,0x34,0x36,0x39,0x3c,0x3f,0x42,0x44,0x47,0x49,0x4c,0x4f,0x51,0x53,0x56,0x58,
  0x5a,0x5c,0x5f,0x61,0x63,0x65,0x67,0x68,0x6a,0x6c,0x6e,0x6f,0x71,0x72,0x73,0x75,
  0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7d,0x7e,0x7e,0x7f,0x7f,0x7f,0x7f,0x7f,
  0x7f,0x7f,0x7f,0x7f,0x7f,0x7e,0x7e,0x7d,0x7d,0x7c,0x7b,0x7b,0x7a,0x79,0x78,0x77,
  0x75,0x74,0x73,0x71,0x70,0x6e,0x6d,0x6b,0x69,0x68,0x66,0x64,0x62,0x60,0x5e,0x5b,
  0x59,0x57,0x55,0x52,0x50,0x4d,0x4b,0x48,0x46,0x43,0x40,0x3d,0x3b,0x38,0x35,0x32,
  0x2f,0x2c,0x29,0x26,0x23,0x20,0x1d,0x1a,0x17,0x14,0x11,0x0e,0x0b,0x07,0x04,0x01,
  0xff,0xfc,0xf9,0xf5,0xf2,0xef,0xec,0xe9,0xe6,0xe3,0xe0,0xdd,0xda,0xd7,0xd4,0xd1,
  0xce,0xcb,0xc8,0xc5,0xc3,0xc0,0xbd,0xba,0xb8,0xb5,0xb3,0xb0,0xae,0xab,0xa9,0xa7,
  0xa5,0xa2,0xa0,0x9e,0x9c,0x9a,0x98,0x97,0x95,0x93,0x92,0x90,0x8f,0x8d,0x8c,0x8b,
  0x89,0x88,0x87,0x86,0x85,0x85,0x84,0x83,0x83,0x82,0x82,0x81,0x81,0x81,0x81,0x81,
  0x81,0x81,0x81,0x81,0x81,0x82,0x82,0x83,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,
  0x8b,0x8d,0x8e,0x8f,0x91,0x92,0x94,0x96,0x98,0x99,0x9b,0x9d,0x9f,0xa1,0xa4,0xa6,
  0xa8,0xaa,0xad,0xaf,0xb1,0xb4,0xb7,0xb9,0xbc,0xbe,0xc1,0xc4,0xc7,0xca,0xcc,0xcf,
  0xd2,0xd5,0xd8,0xdb,0xde,0xe1,0xe4,0xe7,0xeb,0xee,0xf1,0xf4,0xf7,0xfa,0xfd 
};

//-----------------------------------------------
const byte laserPin = 13;
const byte laserPin2 = 12;
const byte tacoPin = 2;

int line = 0;
char Video[] = " HELLO!!!  .... I AM A LASER PROJECTOR BUILT BY RAUL AGUAVIVA MORE INFO COODINGLAB.BLOGSPOT.COM ";

char VideoRam[10];

char *pVideo = Video;

const byte mask[8] = { 
  2,4,8,16,32,64,128};

int beamdelay[8] = { 
  0,0,0,0,0,0,0 };
  
boolean scroll;
unsigned int clockwall;
boolean wave;
boolean FullLaser;
boolean verbose;

volatile unsigned int rpmcount;
unsigned int rpm;

volatile unsigned long markers[7];
volatile boolean ignore = false;
volatile unsigned int start = 0;

void Reset()
{
  scroll = false;
  clockwall = 0;
  start = 0;
  wave = false;
  FullLaser = false;
  verbose = false;
  pVideo = Video;
}

void setup()
{
  Serial.begin(115200);

  pinMode(laserPin, OUTPUT);   // sets the pin as output
  pinMode(laserPin2, OUTPUT);   // sets the pin as output

  pinMode(tacoPin, INPUT);   // sets the pin as output
  digitalWrite( tacoPin, HIGH );     

  rpmcount = 0;
  rpm = 0;

  Serial.println( "Laser Projector Ready!" );      

  Reset();
  
  attachInterrupt(0, rpm_fun, FALLING);
  
}

void RasterLine( byte _line, unsigned int offset )
{
        digitalWrite( laserPin, HIGH );
        return;

  int t = beamdelay[_line];

  if ( wave )
  {
    t += (char)pgm_read_byte( &sin_lut[ (clockwall*16 + _line*16) & 0xff ] )/2;
  }

  for(int i=0;i<t;i++)
  {
    digitalWrite( laserPin, LOW );
    digitalWrite( laserPin2, LOW );
  }

  byte mascara = mask[_line];

  for(byte i=0;i<10;i++)
  {
    for(byte j=0;j<8;j++)
    {
      boolean m = ( pgm_read_byte( &konami_font[ (pVideo[offset>>3]-' ') * 8 + (offset&7)] ) & mascara )?HIGH:LOW;

      if ( FullLaser )
        m = HIGH;

      for(byte k=0;k<1;k++)
      {
        digitalWrite( laserPin, m );
//        digitalWrite( laserPin2, m );
      }
      offset++;
    }       
  }

  digitalWrite( laserPin, LOW );     
  digitalWrite( laserPin2, LOW );     
}


// 8224,7976,8292,7784,8228,8028,7876,
// <    >    <    >    <    >    >
void rpm_fun()
{
    rpmcount++; 
    if (ignore == true)
    {
      return;
    }
    ignore = true;

    static unsigned int olddelta = 0;
    static unsigned int oldtime = 0;
    static byte index = 0;
        
    unsigned long t = micros();
    unsigned int delta = t - oldtime;
    oldtime = t;

   // find pattern that signals first scanline
    static byte cond = 0;
    if ( olddelta > delta )
    {
      cond++;
      if ( cond == 2 )
      {
        index = 3;
        cond = 0;
      }
    }
    else
    {
      cond = 0;
    }

    markers[index] = delta;

    olddelta = delta;

    RasterLine( index, start );

    index++;
    if ( index >6 ) 
    {
      index = 0;

      clockwall++;

      if ( scroll )
      {
        start++;
        if ( start >55*8 )
          start = 0;
      }
    }    
    
    ignore = false;    
}


byte cmd=0;

void DoKeyboard()
{
  if (Serial.available() > 0) 
  {
    ignore = true;
    
    unsigned char in = Serial.read();

    if ( in == 'w' )
    {
      wave = !wave;
    }
    else if ( in == 'v' )
    {
      pVideo = VideoRam;
    }    
    else if ( in == 'V' )
    {
      pVideo = Video;
    }    
    else if ( in >= '0' && in <='9')
    {
      line = in-'0';
      Serial.println( line, DEC );    
    }
    else if ( in == '+' )
    {
      cmd++;      
      if ( line == 8 )
      {
        for(byte i=1;i<7;i++)
        {
          beamdelay[i]++;
        }
      }
      else
      {       
        beamdelay[line]++;
      }
      Serial.println( beamdelay[line], DEC );    
    }
    else if ( in == '-' )
    {
      cmd--;
      if ( line == 8 )
      {
        for(byte i=1;i<7;i++)
        {
          beamdelay[i]--;
        }
      }
      else
      {       
        beamdelay[line]--;
      }
      Serial.println( beamdelay[line], DEC );    
    }
    else if ( in == 'r' )
    {
      Reset();
    }
    else if ( in == 'f' )
    {
      FullLaser = !FullLaser;
    }
    else if ( in == 's' )
    {
      scroll = !scroll;
    }
    else if ( in == ' ' )
    {
      for(byte i=0;i<7;i++)
      {
        Serial.print( beamdelay[i], DEC );    
        Serial.print(',');         
      }
      Serial.println();

      for(byte i=0;i<7;i++)
      {
        Serial.print( markers[i], DEC );    
        Serial.print(',');         
      }
      Serial.println();
    }
    else if ( in == 'q' )
    {
      rpmcount = 0;
      delay (1000);
      Serial.print ((rpmcount *60) / 7, DEC);
      Serial.println (" rpm");
    }

  ignore = false;
  }  
}

// |________|________|________|________|________|________|________|__|_____
// 0        1        2        3        4        5        6        7

//0:10100 ,1:9676 ,2:10116 ,3:9744 ,4:9840 ,5:10056 ,6:9868 
// <       >        <        >       <       <        >



unsigned long lastlap;
unsigned int t1;
boolean lastcmp = true;

byte scanline = 0;



void loop()
{
  DoKeyboard();  
}





//----------------------------------------------- 



